#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netlink.h>
#include <net/sock.h>
#include <linux/skbuff.h>

#define NETLINK_TEST 29

#define NL_GET 0x10
#define NL_SET 0x11

#define MAXPALOAD 64

static struct sock *nl_sk;
static DEFINE_MUTEX(netlink_mutex);

struct timer_list timer;

__u32  app_pid = -1;


static int netlink_send(__u32 pid, const void *buf, size_t count)
{
    struct sk_buff *skb;
    struct nlmsghdr *rep;

    // 创建一个新的sk_buff，使用NLMSG_SPACE来分配足够的空间
    skb = nlmsg_new(NLMSG_SPACE(count), GFP_KERNEL);
    if (!skb) {
        pr_err("nlmsg_new error\n");
        return -1;
    }

    // 构造Netlink消息头
    rep = nlmsg_put(skb, 0, 0, 0, count, 0);
    if (!rep) {
        kfree_skb(skb);
        return -1;
    }

    // 复制数据到消息体
    memcpy(NLMSG_DATA(rep), buf, count);

    // 发送消息
    return netlink_unicast(nl_sk, skb, pid, MSG_DONTWAIT);
}


static short testArray[20] = {0};

static void initialize_array(short *array, int size) {
    int i = 0;

    for (i = 0; i < size; ++i) {
        array[i] = (short)i;
    }
}



static void hp_timer_function(struct timer_list *unused)
{

     initialize_array(testArray, sizeof(testArray) / sizeof(short));
        netlink_send(app_pid, testArray, sizeof(testArray));

	mod_timer(&timer, jiffies + msecs_to_jiffies(20 * 50 * 5));
        return;
}


static int netlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, struct netlink_ext_ack *extack)
{

    app_pid = nlh->nlmsg_pid;

    timer_setup(&timer, hp_timer_function, 0);
    mod_timer(&timer, jiffies + msecs_to_jiffies(20 * 50 * 5));

    return ;
}

static void netlink_rcv(struct sk_buff *skb)
{
    mutex_lock(&netlink_mutex);
    netlink_rcv_skb(skb, &netlink_rcv_msg);
    mutex_unlock(&netlink_mutex);
}

static int __init netlink_init(void)
{
    struct netlink_kernel_cfg cfg = {
        .input = netlink_rcv,
    };

    nl_sk = netlink_kernel_create(&init_net, NETLINK_TEST, &cfg);
    if (!nl_sk) {
        pr_warn("Failed to create netlink socket\n");
        return -ENOMEM;
    }

    return 0;
}

static void __exit netlink_exit(void)
{
    del_timer_sync(&timer);
    netlink_kernel_release(nl_sk);
}

MODULE_LICENSE("Dual BSD/GPL");
module_init(netlink_init);
module_exit(netlink_exit);
